#pragma once


// Printing
#define PRINT(x)    std::cout << "["; thrust::copy(x.begin(), x.end(), std::ostream_iterator<int>(std::cout, ", ")); std::cout << "]" << std::endl
#define PRINf(x)    std::cout << "["; thrust::copy(x.begin(), x.end(), std::ostream_iterator<float>(std::cout, ", ")); std::cout << "]" << std::endl
#define PRIN2(x,y)  std::cout << "["; thrust::copy(x, y, std::ostream_iterator<int>(std::cout, ", ")); std::cout << "]" << std::endl
#define PRIN2f(x,y) std::cout << "["; thrust::copy(x, y, std::ostream_iterator<float>(std::cout, ", ")); std::cout << "]" << std::endl


struct event_pair
{
  cudaEvent_t start;
  cudaEvent_t end;
};


inline void start_timer(event_pair * p)
{
  cudaEventCreate(&p->start);
  cudaEventCreate(&p->end);
  cudaEventRecord(p->start, 0);
}


inline float stop_timer(event_pair * p, char *name)
{
  cudaEventRecord(p->end, 0);
  cudaEventSynchronize(p->end);

  float elapsed_time;
  cudaEventElapsedTime(&elapsed_time, p->start, p->end);
  printf("%s took %.1f ms\n",name, elapsed_time);
  cudaEventDestroy(p->start);
  cudaEventDestroy(p->end);
  return elapsed_time;
}

inline void check_cuda_error(const char *message, const char *filename, const int lineno)
{
  cudaThreadSynchronize();
  cudaError_t error = cudaGetLastError();
  if(error != cudaSuccess)
  {
    printf("CUDA error after %s at %s:%d: %s\n", message, filename, lineno, cudaGetErrorString(error));
    exit(-1);
  }
}

__host__ __device__
inline unsigned int next_rand(unsigned int rnd)
{
  return (1103515245 * rnd + 12345) & 0x7fffffffUL;
}


__host__ __device__
inline unsigned int max_rand()
{
  return 0x7fffffffUL;
}

//unsigned long isqrt(unsigned long x)
//{
//    register unsigned long op, res, one;
//
//    op = x;
//    res = 0;
//
//    /* "one" starts at the highest power of four <= than the argument. */
//    one = 1 << 30;  /* second-to-top bit set */
//    while (one > op) one >>= 2;
//
//    while (one != 0) {
//        if (op >= res + one) {
//            op -= res + one;
//            res += one << 1;  // <-- faster than 2 * one
//        }
//        res >>= 1;
//        one >>= 2;
//    }
//    return res;
//}
//
//unsigned long uisqrt(unsigned long x)
//{
//    unsigned long isq = isqrt(x);
//    return (isq * isq == x) ? isq : (isq+1);
//}
